package com.hfut.wxy.common.config;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * redis cache config
 */
@Configuration
@EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport {
    /**
     *  缓存管理器
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        Map<String, RedisCacheConfiguration> map = getRedisCacheConfigurationMap();
        Set<String> keySet = map.keySet();
        // 初始化的缓存空间set集合
        Set<String> cacheNames =  new HashSet<>();
        // 每个缓存空间不同的配置
        Map<String, RedisCacheConfiguration> configMap = new HashMap<>(keySet.size());

        for (String key:keySet) {
            cacheNames.add(key);
            configMap.put(key,map.get(key));
        }
        // 使用自定义的缓存配置初始化一个cacheManager
        return RedisCacheManager.builder(redisConnectionFactory)
                // 注意initialCacheNames withInitialCacheConfigurations调用顺序，一定要先调用该方法设置初始化的缓存名，再初始化相关的配置
                .initialCacheNames(cacheNames)
                .withInitialCacheConfigurations(configMap)
                .build();
    }

    /**
     * 自定义配置缓存配置
     */
    private Map<String, RedisCacheConfiguration> getRedisCacheConfigurationMap() {
        // 初始化一个默认模板config
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
        redisCacheConfiguration = redisCacheConfiguration.entryTtl(Duration.ofMinutes(1))// 设置缓存的默认过期时间，也是使用Duration设置
                .disableCachingNullValues();     // 不缓存空值

        Map<String, RedisCacheConfiguration> map =new HashMap<>(16);
        /* 自定义配置 **/
        /*
        1min 不缓存空值
         */
        map.put("redisCache",redisCacheConfiguration);
        /*
        120s 不缓存空值
         */
        map.put("redisCache2", redisCacheConfiguration.entryTtl(Duration.ofSeconds(120)));
        return map;
    }


    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        // String 序列化方式
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // Jackson 序列化方式
//        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//        ObjectMapper om = new ObjectMapper();
//        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
//        jackson2JsonRedisSerializer.setObjectMapper(om);

        FastJsonRedisSerializer<?> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
        FastJsonConfig fastJsonConfig = fastJsonRedisSerializer.getFastJsonConfig();
        fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
        fastJsonConfig.setCharset(StandardCharsets.UTF_8);
        fastJsonConfig.setSerializerFeatures(
                //是否输出null字段
                SerializerFeature.WriteMapNullValue,
                //集合输出[]而非null
                SerializerFeature.WriteNullListAsEmpty,
                //字符串输出""而非null
                SerializerFeature.WriteNullStringAsEmpty,
                //关闭重复引用
                SerializerFeature.DisableCircularReferenceDetect,
                //数字输出为0
                SerializerFeature.WriteNullNumberAsZero,
                //boolean 输出为false
                SerializerFeature.WriteNullBooleanAsFalse,
//                SerializerFeature.WriteNonStringValueAsString,
                SerializerFeature.WriteEnumUsingToString,
                SerializerFeature.PrettyFormat
        );
        /* template */
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(stringRedisSerializer);
        template.setHashKeySerializer(stringRedisSerializer);
        template.setValueSerializer(fastJsonRedisSerializer);
        template.setHashValueSerializer(fastJsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}